package com.zp.oauth2.gateway.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.benmanes.caffeine.cache.*;
import com.zp.common.base.constant.Atom;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.List;
import java.util.Map;


/**
 * 系统配置类,重写redis序列化和Caffeine配置
 *
 * @author zp
 */
@Configuration
@Slf4j
public class SystemConfig {


    @Bean
    public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // Key序列话
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);

        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // value序列化
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);


        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

    /**
     * 本地咖啡因缓存，存储权限信息减轻redis压力
     *
     */
    @Bean
    public LoadingCache  localCaffeineCache(RedisTemplate redisTemplate){
    return Caffeine.newBuilder().
                maximumSize(1000).
                removalListener((RemovalListener<String, Map<String, List<String>>>)
                        (key, value, cause) -> log.info("移除了缓存--{},缓存值为--{},移除原因--{}",key,value,cause)).
                build(new CacheLoader<String, Map<String, List<String>>>() {
                    @Override
                    public @Nullable Map<String, List<String>> load(@NonNull String key) throws Exception {
                        //获取所有的uri->角色对应关系
                        return redisTemplate.opsForHash().entries(Atom.OAUTH_URLS);
                    }
                });

    }
}
